package net.sf.nlp.ltag.gui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import net.sf.nlp.ltag.data.LTAGNode;
import net.sf.nlp.ltag.data.LTAGTree;
import net.sf.nlp.ltag.parser.LTAGParser;
import net.sf.nlp.ltag.parser.ParserTree;
import net.sf.nlp.ltag.util.GraphViz;
import net.sf.nlp.ltag.util.LTAG;

@SuppressWarnings("serial")
public class ParserFrame extends JFrame implements ActionListener, ChangeListener, ItemListener {
	
	JPanel panel = new JPanel();
	TreePanel parserTreePanel;
	JTextArea inputText;
	JLabel statusLabel;
	JButton parserBtn;
	JButton treeShowBtn;

	JComboBox algComboBox;
	JCheckBox multiThreadCheckBox;
	JSpinner bestNSpinner;
	JSpinner filterBestNSpinner;
	
	JMenuItem exitMenuItem;
	JMenuItem helpMenuItem;
	JMenuItem aboutMenuItem;
	
	LTAGParser parser = new LTAGParser();

	public ParserFrame() {
		init();
	}

	private void init() 
	{
		setTitle("句法分析");
		//setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		addWindowListener(new WindowAdapter() 
			{ 
				public void windowClosing(WindowEvent e) 
				{ 
					LTAG.saveLtagProperties();
					System.exit(0); 
				} 
			}
		);
		
		addToolBar();
		addMenu();
		
		JPanel topPanel = new JPanel();
		JToolBar statusBar = new JToolBar();
		
		parserTreePanel = new TreePanel();
		statusLabel = new JLabel(" ");
		statusLabel.setHorizontalAlignment(SwingConstants.LEFT);
		
		statusBar.setFloatable(false);
		statusBar.add(statusLabel);
		
		topPanel.setMinimumSize(new Dimension(100, 500));
		topPanel.setPreferredSize(new Dimension(50, 100));
		topPanel.setLayout(new BorderLayout());

		addInputText(topPanel);
		addButtons(topPanel);
		
		panel.setLayout(new BorderLayout());
		panel.add(topPanel, BorderLayout.NORTH);
		panel.add(parserTreePanel, BorderLayout.CENTER);
		panel.add(statusBar, BorderLayout.SOUTH);
		
		add(panel);
	}
	
	private void addToolBar()
	{
		JToolBar toolBar = new JToolBar();
		
		toolBar.setFloatable(false);
		toolBar.setRollover(true);
		
		algComboBox = new JComboBox(new String[]{"Dot", "Earley"});
		algComboBox.setMaximumSize(new Dimension(60,30)); 
		algComboBox.setSelectedIndex(Boolean.valueOf(LTAG.ltagProperties.getProperty("USER_EARLEY_PARSER")) ? 1 : 0);
		algComboBox.addItemListener(this);
		
		bestNSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 100, 1));
		bestNSpinner.setMaximumSize(new Dimension(50,25)); 
		bestNSpinner.setValue(Integer.valueOf(LTAG.ltagProperties.getProperty("BEST_RESULT_COUNT")));
		bestNSpinner.addChangeListener(this);
		
		filterBestNSpinner = new JSpinner(new SpinnerNumberModel(1, 0, 1000, 1));
		filterBestNSpinner.setMaximumSize(new Dimension(50,25)); 
		filterBestNSpinner.setValue(Integer.valueOf(LTAG.ltagProperties.getProperty("FILTER_BEST_COUNT")));
		filterBestNSpinner.addChangeListener(this);
		
		multiThreadCheckBox = new JCheckBox("多线程");
		multiThreadCheckBox.setSelected(Boolean.valueOf(LTAG.ltagProperties.getProperty("MULTI_THREAD")));
		multiThreadCheckBox.addChangeListener(this);
		
		toolBar.add(new JLabel("算法:"));
		toolBar.addSeparator();
		toolBar.add(algComboBox);
		toolBar.addSeparator();
		toolBar.add(multiThreadCheckBox);
		toolBar.add(new JLabel("Best Result Count:"));
		toolBar.add(bestNSpinner);
		toolBar.add(new JLabel("Filter Best Count:"));
		toolBar.add(filterBestNSpinner);
		
		getContentPane().add(toolBar, BorderLayout.NORTH);
	}
	
	private void addMenu()
	{
		JMenuBar menuBar = new JMenuBar();  
        setJMenuBar(menuBar); 
        
        JMenu fileMenu = new JMenu("文件(F)");  
        fileMenu.setMnemonic('F');  
        menuBar.add(fileMenu);  
  
        exitMenuItem = new JMenuItem("退出(X)");  
        exitMenuItem.setMnemonic('X');  
        exitMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK));
        exitMenuItem.addActionListener(this);
        fileMenu.add(exitMenuItem); 
        
        JMenu settingMenu = new JMenu("设置(S)");  
        settingMenu.setMnemonic('S');  
        menuBar.add(settingMenu);  
        
        JMenuItem settingMenuItem = new JMenuItem("设置(S)...");  
        settingMenuItem.setMnemonic('S');  
        settingMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK));  
        settingMenu.add(settingMenuItem); 
        
        JMenu helpMenu = new JMenu("帮助(H)");  
        helpMenu.setMnemonic('H');  
        menuBar.add(helpMenu);
        
        helpMenuItem = new JMenuItem("使用帮助(U)");  
        helpMenuItem.setMnemonic('U');  
        helpMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_U, InputEvent.CTRL_MASK)); 
        helpMenuItem.addActionListener(this);
        helpMenu.add(helpMenuItem); 
        helpMenu.addSeparator();
        
        aboutMenuItem = new JMenuItem("关于(A)...");  
        aboutMenuItem.setMnemonic('S');  
        aboutMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_MASK));  
        aboutMenuItem.addActionListener(this);
        helpMenu.add(aboutMenuItem); 
	}
	
	private void addInputText(JPanel topPanel) {
		inputText = new JTextArea();
		
		JScrollPane scrollPane = new JScrollPane(inputText);

		Dimension minimumSize = new Dimension(100, 500);
		scrollPane.setMinimumSize(minimumSize);
		scrollPane.setPreferredSize(new Dimension(700, 400));

		topPanel.add(scrollPane, BorderLayout.CENTER);
	}
	
	private void addButtons(JPanel topPanel) {
		
		JPanel buttonPanel = new JPanel();
		buttonPanel.setLayout(new GridLayout(2, 1));
		
		parserBtn = new JButton("句法分析");
		parserBtn.addActionListener(this);

		treeShowBtn= new JButton("显示树结构");
		treeShowBtn.addActionListener(this);
		
		buttonPanel.add(parserBtn);
		buttonPanel.add(treeShowBtn);
		
		topPanel.add(buttonPanel, BorderLayout.EAST);
	}

	public void toCenter() {
		// ---------------------------设置窗口居中----------------------------------------------------------
		int windowWidth = getWidth(); // 获得窗口宽
		int windowHeight = getHeight(); // 获得窗口高
		Toolkit kit = Toolkit.getDefaultToolkit(); // 定义工具包
		Dimension screenSize = kit.getScreenSize(); // 获取屏幕的尺寸
		int screenWidth = screenSize.width; // 获取屏幕的宽
		int screenHeight = screenSize.height; // 获取屏幕的高
		setLocation(screenWidth / 2 - windowWidth / 2, screenHeight / 2
				- windowHeight / 2);// 设置窗口居中显示
		// ------------------------------------------------------------------------------------------------
	}

	private static void createAndShowGUI() {
		ParserFrame frame = new ParserFrame();

		frame.pack();
		frame.toCenter();
		frame.setVisible(true);
	}

	public static void main(String[] args) {
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				createAndShowGUI();
			}
		});
	}

	@Override
	public void actionPerformed(ActionEvent event) {
		if (event.getSource() == parserBtn) {
			parserSentence(inputText.getText().trim());
		}
		else if(event.getSource() == treeShowBtn)
		{
			parserTreeBank(inputText.getText().trim());
		}
		else if (event.getSource() == exitMenuItem)
		{
			System.exit(0);
		}
		else if (event.getSource() == helpMenuItem)
		{
			try 
			{
				String helpFile = Thread.currentThread().getContextClassLoader().getResource("").toString() + "help.html";
				Runtime.getRuntime().exec("cmd.exe /c start " + helpFile);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		else if (event.getSource() == aboutMenuItem)
		{
			
		}
	}

	@Override
	public void stateChanged(ChangeEvent event) 
	{
		if (event.getSource() == multiThreadCheckBox)
		{
			if (Boolean.valueOf(LTAG.ltagProperties.getProperty("MULTI_THREAD")).equals(multiThreadCheckBox.isSelected()))
				return;
			
			LTAG.ltagProperties.setProperty("MULTI_THREAD", String.valueOf(multiThreadCheckBox.isSelected()));
			parser = new LTAGParser();
		}
		else if (event.getSource() == bestNSpinner)
		{
			LTAG.ltagProperties.setProperty("BEST_RESULT_COUNT", String.valueOf(bestNSpinner.getValue()));
		}
		else if (event.getSource() == filterBestNSpinner)
		{
			LTAG.ltagProperties.setProperty("FILTER_BEST_COUNT", String.valueOf(filterBestNSpinner.getValue()));
		}	
	}
	
	@Override
	public void itemStateChanged(ItemEvent event) 
	{
		if (event.getSource() == algComboBox)
		{
			if (Boolean.valueOf(LTAG.ltagProperties.getProperty("USER_EARLEY_PARSER")).equals(algComboBox.getSelectedIndex() == 1))
				return;
			
			LTAG.ltagProperties.setProperty("USER_EARLEY_PARSER", String.valueOf(algComboBox.getSelectedIndex() == 1));
			parser = new LTAGParser();
		}
	}
	
	private void parserSentence(String text) 
	{
		setStatusText("开始句法分析....");
		
		long startTime = System.currentTimeMillis();
		List<ParserTree> parserTrees = parser.parser(text);
		long costTime = System.currentTimeMillis() - startTime;
		
		setStatusText("句法分析结束,共耗时" + costTime + ". ");
		
		if (parserTrees == null)
		{
			appendStatusText("没有找到匹配的句法树");
			return;
		}
		
		final List<LTAGTree> trees = new ArrayList<LTAGTree>();

		for (ParserTree parserTree : parserTrees)
			trees.add(parserTree.getTree());

		parserTreePanel.setResult("cost time:" + costTime);
		parserTreePanel.setTrees(trees);
		
		new GenerateGraph(parserTrees).start();
	}
	
	private void parserTreeBank(String text)
	{
		LTAGNode root = LTAG.buildLTAGNodeFromText(text, true);
    	
		if (root == null)
			return;
		
    	LTAGTree tree = new LTAGTree();
    	tree.setRoot(root);
    	tree.generateNodeLocation();
    	
    	final List<LTAGTree> trees = new ArrayList<LTAGTree>();
    	final List<ParserTree> parserTrees = new ArrayList<ParserTree>();
    	
    	trees.add(tree);
    	parserTrees.add(new ParserTree(tree, 0));
    	
    	//List<File> graphFiles = GraphViz.getGraphViz(parserTrees);
    	
    	parserTreePanel.setTrees(trees);
    	//parserTreePanel.setGraphs(graphFiles);
    	new GenerateGraph(parserTrees).start();
	}
	
	private void setStatusText(String message)
	{
		statusLabel.setText(message);
		
		statusLabel.updateUI();
	}
	
	private void appendStatusText(String message)
	{
		statusLabel.setText(statusLabel.getText() + " " +  message);
		
		statusLabel.updateUI();
	}
	
	class GenerateGraph extends Thread
	{
		private List<ParserTree> parserTrees;
		
		public GenerateGraph(List<ParserTree> parserTrees)
		{
			this.parserTrees = parserTrees;
		}
		
		public void run()
		{
			appendStatusText("正在生成句法树图形文件....");
			
			List<File> graphFiles = GraphViz.getGraphViz(parserTrees);
			
			parserTreePanel.setGraphs(graphFiles);
			
			setStatusText("句法树图形文件生成完毕");
		}
	}
}
